package org.cainiao.api.lark.impl.imperative.authenticateandauthorize.getaccesstokens;

import lombok.RequiredArgsConstructor;
import org.cainiao.api.lark.dto.response.LarkDataResponse;
import org.cainiao.api.lark.dto.response.authenticateandauthorize.getaccesstokens.LarkTokenInfo;
import org.cainiao.api.lark.imperative.authenticateandauthorize.getaccesstokens.restoperations.GetAccessTokensWithAppAccessToken;
import org.cainiao.api.lark.impl.util.converter.ResponseConverter;
import org.cainiao.api.lark.impl.util.provider.LarkAppAccessTokenProvider;
import org.cainiao.api.lark.util.Util;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;

import java.util.Map;

import static org.cainiao.api.lark.util.Util.AUTHEN_MODULE_URI;

/**
 * 靠 RestOperations 切换 HTTP 客户端<br />
 * <p>
 * Author: Cai Niao(wdhlzd@163.com)<br />
 */
@RequiredArgsConstructor
public class WebClientGetAccessTokensWithAppAccessToken implements GetAccessTokensWithAppAccessToken {

    private final WebClient webClient;
    private final String baseUrl;
    private final LarkAppAccessTokenProvider larkAppAccessTokenProvider;
    private final ResponseConverter responseConverter;

    @Override
    public ResponseEntity<LarkDataResponse<LarkTokenInfo>> refreshUserAccessToken(String refreshToken) {
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("grant_type", "refresh_token");
        formData.add("refresh_token", refreshToken);
        WebClient.RequestBodySpec requestBodySpec = webClient.post()
            .uri(String.format("%s%s/oidc/refresh_access_token", baseUrl, AUTHEN_MODULE_URI))
            .contentType(MediaType.APPLICATION_JSON)
            .accept(MediaType.APPLICATION_JSON);
        Util.setAccessToken(requestBodySpec, larkAppAccessTokenProvider);
        return requestBodySpec.body(BodyInserters.fromFormData(formData))
            .exchangeToMono(clientResponse -> clientResponse
                .bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
                })
                .map(responseMap -> ResponseEntity
                    .status(clientResponse.statusCode())
                    .headers(clientResponse.headers().asHttpHeaders())
                    .body(responseConverter.convertToLarkTokenInfoResponse(responseMap))))
            .onErrorResume(WebClientResponseException.class, e -> Mono.just(ResponseEntity.status(e.getStatusCode()).build()))
            .block();
    }
}
